#include "systemc.h"
#include "cache.h"
#include "cache_controller.h"
#include "ram.h"
#include "victim_cache.h"

int sc_main(int argc, char *argv[])
{
  /* CPU */
  sc_signal< sc_logic >  cs;
  sc_signal< sc_logic >  rw;
  sc_signal< sc_lv<32> > addr;
  sc_signal< sc_lv<32> > din;
  sc_signal< sc_logic  > rdy;
  sc_signal< sc_lv<32> > dout;

  /* RAM */
  sc_signal< sc_logic  > m_rdy;
  sc_signal< sc_lv<32> > m_dout0;
  sc_signal< sc_lv<32> > m_dout1;
  sc_signal< sc_lv<32> > m_dout2;
  sc_signal< sc_lv<32> > m_dout3;
  sc_signal< sc_logic >  m_cs;
  sc_signal< sc_logic >  m_rw;
  sc_signal< sc_lv<32> > m_addr;
  sc_signal< sc_lv<32> > m_din0;
  sc_signal< sc_lv<32> > m_din1;
  sc_signal< sc_lv<32> > m_din2;
  sc_signal< sc_lv<32> > m_din3;

  /* VICTIM CACHE*/
  sc_signal< sc_logic >  v_rdy;
  sc_signal< sc_logic >  v_hit;
  sc_signal< sc_lv<30> > v_tout;
  sc_signal< sc_lv<32> > v_dout0;
  sc_signal< sc_lv<32> > v_dout1;
  sc_signal< sc_lv<32> > v_dout2;
  sc_signal< sc_lv<32> > v_dout3;
  sc_signal< sc_logic >  v_cs;
  sc_signal< sc_logic >  v_rw;
  sc_signal< sc_lv<32> > v_addr;
  sc_signal< sc_lv<32> > v_din0;
  sc_signal< sc_lv<32> > v_din1;
  sc_signal< sc_lv<32> > v_din2;
  sc_signal< sc_lv<32> > v_din3;
  sc_signal< sc_logic >  v_set_v;   
  sc_signal< sc_logic >  v_set_d;

  /* CACHE */
  sc_signal< sc_logic >  c_rdy;
  sc_signal< sc_logic >  c_hit;
  sc_signal< sc_lv<25> > c_tout;
  sc_signal< sc_lv<32> > c_dout0;
  sc_signal< sc_lv<32> > c_dout1;
  sc_signal< sc_lv<32> > c_dout2;
  sc_signal< sc_lv<32> > c_dout3;

  sc_signal< sc_logic >  c_cs;
  sc_signal< sc_logic >  c_rw;
  sc_signal< sc_lv<32> > c_addr;
  sc_signal< sc_lv<32> > c_din0;
  sc_signal< sc_lv<32> > c_din1;
  sc_signal< sc_lv<32> > c_din2;
  sc_signal< sc_lv<32> > c_din3;
  sc_signal< sc_logic >  c_set_v;   
  sc_signal< sc_logic >  c_din_src;

  /* STATE */
  sc_signal< sc_lv<3> >  state;

  cache_controller cc("CACHE_CONTROLLER");
  cc.cs(cs);
  cc.rw(rw);
  cc.addr(addr);
  cc.din(din);
  cc.rdy(rdy);
  cc.dout(dout);
  cc.m_rdy(m_rdy);
  cc.m_dout0(m_dout0);
  cc.m_dout1(m_dout1);
  cc.m_dout2(m_dout2);
  cc.m_dout3(m_dout3);
  cc.m_cs(m_cs);
  cc.m_rw(m_rw);
  cc.m_addr(m_addr);
  cc.m_din0(m_din0);
  cc.m_din1(m_din1);
  cc.m_din2(m_din2);
  cc.m_din3(m_din3);
  cc.v_rdy(v_rdy);
  cc.v_hit(v_hit);
  cc.v_tout(v_tout);
  cc.v_dout0(v_dout0);
  cc.v_dout1(v_dout1);
  cc.v_dout2(v_dout2);
  cc.v_dout3(v_dout3);
  cc.v_cs(v_cs);
  cc.v_rw(v_rw);
  cc.v_addr(v_addr);
  cc.v_din0(v_din0);
  cc.v_din1(v_din1);
  cc.v_din2(v_din2);
  cc.v_din3(v_din3);
  cc.v_set_v(v_set_v);   
  cc.v_set_d(v_set_d);
  cc.c_rdy(c_rdy);
  cc.c_hit(c_hit);
  cc.c_tout(c_tout);
  cc.c_dout0(c_dout0);
  cc.c_dout1(c_dout1);
  cc.c_dout2(c_dout2);
  cc.c_dout3(c_dout3);
  cc.c_cs(c_cs);
  cc.c_rw(c_rw);
  cc.c_addr(c_addr);
  cc.c_din0(c_din0);
  cc.c_din1(c_din1);
  cc.c_din2(c_din2);
  cc.c_din3(c_din3);
  cc.c_set_v(c_set_v);   
  cc.c_din_src(c_din_src);
  cc.state(state);

  cache c("CACHE");
  c.rdy(c_rdy);
  c.hit(c_hit);
  c.tout(c_tout);
  c.dout0(c_dout0);
  c.dout1(c_dout1);
  c.dout2(c_dout2);
  c.dout3(c_dout3);
  c.cs(c_cs);
  c.rw(c_rw);
  c.addr(c_addr);
  c.din0(c_din0);
  c.din1(c_din1);
  c.din2(c_din2);
  c.din3(c_din3);
  c.set_v(c_set_v);   
  c.din_src(c_din_src);

  victim_cache v("VICTIM_CACHE");
  v.rdy(v_rdy);
  v.hit(v_hit);
  v.tout(v_tout);
  v.dout0(v_dout0);
  v.dout1(v_dout1);
  v.dout2(v_dout2);
  v.dout3(v_dout3);
  v.cs(v_cs);
  v.rw(v_rw);
  v.addr(v_addr);
  v.din0(v_din0);
  v.din1(v_din1);
  v.din2(v_din2);
  v.din3(v_din3);
  v.set_v(v_set_v);   
  v.set_d(v_set_d);

  ram m("RAM");
  m.rdy(m_rdy);
  m.dout0(m_dout0);
  m.dout1(m_dout1);
  m.dout2(m_dout2);
  m.dout3(m_dout3);
  m.cs(m_cs);
  m.rw(m_rw);
  m.addr(m_addr);
  m.din0(m_din0);
  m.din1(m_din1);
  m.din2(m_din2);
  m.din3(m_din3);

  sc_trace_file *f = sc_create_vcd_trace_file("c_wave");

  f->set_time_unit(100, SC_PS);

  sc_trace(f, cc.cs, "cs");
  sc_trace(f, cc.rw, "rw");
  sc_trace(f, cc.addr, "addr");
  sc_trace(f, cc.din, "din");
  sc_trace(f, cc.rdy, "rdy");
  sc_trace(f, cc.dout, "dout");
  sc_trace(f, cc.m_rdy, "m_rdy");
  sc_trace(f, cc.m_dout0, "m_dout0");
  sc_trace(f, cc.m_dout1, "m_dout1");
  sc_trace(f, cc.m_dout2, "m_dout2");
  sc_trace(f, cc.m_dout3, "m_dout3");
  sc_trace(f, cc.m_cs, "m_cs");
  sc_trace(f, cc.m_rw, "m_rw");
  sc_trace(f, cc.m_addr, "m_addr");
  sc_trace(f, cc.m_din0, "m_din0");
  sc_trace(f, cc.m_din1, "m_din1");
  sc_trace(f, cc.m_din2, "m_din2");
  sc_trace(f, cc.m_din3, "m_din3");
  sc_trace(f, cc.v_rdy, "v_rdy");
  sc_trace(f, cc.v_hit, "v_hit");
  sc_trace(f, cc.v_tout, "v_tout");
  sc_trace(f, cc.v_dout0, "v_dout0");
  sc_trace(f, cc.v_dout1, "v_dout1");
  sc_trace(f, cc.v_dout2, "v_dout2");
  sc_trace(f, cc.v_dout3, "v_dout3");
  sc_trace(f, cc.v_cs, "v_cs");
  sc_trace(f, cc.v_rw, "v_rw");
  sc_trace(f, cc.v_addr, "v_addr");
  sc_trace(f, cc.v_din0, "v_din0");
  sc_trace(f, cc.v_din1, "v_din1");
  sc_trace(f, cc.v_din2, "v_din2");
  sc_trace(f, cc.v_din3, "v_din3");
  sc_trace(f, cc.v_set_v, "v_set_v");   
  sc_trace(f, cc.v_set_d, "v_set_d");
  sc_trace(f, cc.c_rdy, "c_rdy");
  sc_trace(f, cc.c_hit, "c_hit");
  sc_trace(f, cc.c_tout, "c_tout");
  sc_trace(f, cc.c_dout0, "c_dout0");
  sc_trace(f, cc.c_dout1, "c_dout1");
  sc_trace(f, cc.c_dout2, "c_dout2");
  sc_trace(f, cc.c_dout3, "c_dout3");
  sc_trace(f, cc.c_cs, "c_cs");
  sc_trace(f, cc.c_rw, "c_rw");
  sc_trace(f, cc.c_addr, "c_addr");
  sc_trace(f, cc.c_din0, "c_din0");
  sc_trace(f, cc.c_din1, "c_din1");
  sc_trace(f, cc.c_din2, "c_din2");
  sc_trace(f, cc.c_din3, "c_din3");
  sc_trace(f, cc.c_set_v, "c_set_v");   
  sc_trace(f, cc.c_din_src, "c_din_src");
  sc_trace(f, cc.state, "state");

  // TODO: good test
  /* start sim */
   cs.write(SC_LOGIC_0);
   rw.write(SC_LOGIC_0);
   addr.write(0x00000004);
   din.write(0);
   sc_start(2, SC_NS);

   cs.write(SC_LOGIC_1);
   rw.write(SC_LOGIC_1);
   din.write(0xFFFFFFFF);
   sc_start(180, SC_NS);

   cs.write(SC_LOGIC_0);
   rw.write(SC_LOGIC_0);
   din.write(0x00000000);
   sc_start(10, SC_NS);

   addr.write(0x00000204);
   cs.write(SC_LOGIC_1);
   sc_start(220, SC_NS);

   cs.write(SC_LOGIC_0);
   sc_start(10, SC_NS);

   addr.write(0x00000004);
   cs.write(SC_LOGIC_1);
   sc_start(320, SC_NS);

   cs.write(SC_LOGIC_0);
   sc_start(10, SC_NS);

   cs.write(SC_LOGIC_1);
   sc_start(3, SC_NS);
}
